home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / g_quake / motion.zip / MOTION.QC < prev    next >
Text File  |  1996-08-12  |  13KB  |  404 lines

  1. /*
  2.  
  3.     SECURITY MOTION-DETECTORS
  4.     Author: KTGOW
  5.  
  6.     Started 08/10/96
  7.     Version 1 ready : 08/11/96
  8.     Version 1 released : 08/12/96
  9.  
  10.     Motion detectors are small objects placed by the player.  They attach
  11.     themselves to whatever surface they hit first (walls, ceilings, floors,
  12.     whatever.   Not people).  Once attached, they go into "Security Mode."
  13.     While in a security mode, the motion detector will fire a stream of
  14.     shots at any monsters or players that are a)moving, and b)within a
  15.     2000-unit radius.  The motion detectors do a fairly good job of
  16.     anticipating the movement of a target.
  17.  
  18.     Motion detectors can be destroyed.  When they are destroyed, they
  19.     explode like a grenade.
  20.  
  21.     If 2 or more motion detectors within a 750-unit radius of each other can
  22.     see each other, each of them will destroy itself upon activation;
  23.  
  24.     Once the motion detector is attached to a surface, there is a 10-second
  25.     delay for you to run away before it kills you.
  26.  
  27.     A motion detector requires 50 nails, 95 health, and 1 rocket to create.
  28.     This is nonrefundable.
  29.  
  30.     Motion detectors originally start with 50 shots.  Once they are out
  31.     of ammo, their rate of fire slows to 1 shot every 2 seconds.
  32.     Impulse 16 reloads a Detector in 25-nail increments (taken from
  33.     your own ammo supply).  Detectors can store a maximum of 200 shots.
  34.     If you give a motion detector some nails, it will stop shooting for
  35.     3 seconds in order to load the nails.
  36.  
  37.     Motion detectors kill people indiscriminantly.  A motion detector will
  38.     kill its owner.  Nobody gets credit for a kill done by a motion detector.
  39.  
  40.  
  41.  
  42.  
  43.     To add:
  44.     Motion detectors attack enemy motion detectors?
  45.       No.  Unrealistic.
  46.     Motion detectors explode on contact with players/monsters?
  47.       -Only while in air?
  48.       No.  Unrealistic.  Solves a bug, though (see below).
  49.     Motion detectors need to be given ammo?
  50.       Done.  08/11/96
  51.       -Different types of ammo?  Weapon cycling?
  52.       Scary.  ...but possible.  I've started some work on this.
  53.       -Reloads?
  54.       Done.  08/11/96
  55.     Living motion detectors?
  56.       -Spawning children?
  57.       Talk about unrealistic...
  58.       -Generational improvements/mutations?
  59.       Hahahahaha.
  60.       -Regeneraing health?
  61.       Again, talk about unrealistic...
  62.       -Moving?
  63.       Hmmmmmm...
  64.     If detector fires lightning underwater, have the usual lightning effects.
  65.       If I allow it to fire different types of weapons, I will
  66.       do this.
  67.     Motion detectors do damage when they explode.
  68.       Done.  08/11/96
  69.  
  70.     Bugs:
  71.     Motion detectors lobbed onto the top of an entity will remain floating
  72.       in the air.  Arr.
  73.     Sometimes motion detectors stick to walls about a foot (virtual) away
  74.       away from the wall itself.
  75.     Motion detectors cannot be hit by shotguns, and can only be hit by
  76.       nailguns from certain angles.  Rockets & grenades work fine.
  77.     Sometimes motion detectors fall out of the world when tossed.  :(
  78.  
  79. */
  80.  
  81. // Functions called in MOTION.QC that are defined after its position in
  82. // PROGS.SRC:
  83. void() GrenadeExplode;
  84. void() BecomeExplosion;
  85. void(vector org, vector dir) launch_spike;
  86. void(float damage) spawn_touchblood;
  87. //void(entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  88.  
  89. // Functions defined in MOTION.QC:
  90. void() W_FireMotion;
  91. void() MotionTouch_Moving;
  92. void() MotionThink_Startup;
  93. void() MotionThink_Security;
  94. void(entity targ) MotionFire_Nailgun;
  95. void() MotionThink_Destroy;
  96. void() MotionTouch_Spike;
  97. void() GiveMotionNails;
  98. void() Motion_SwitchWeapon;
  99.  
  100.  
  101. void() W_FireMotion =
  102. {
  103.     local entity detector;
  104.  
  105.     // Check ammo & health requirements...
  106.     if (self.health <= 95 || self.ammo_nails < 50 || self.ammo_rockets < 1)
  107.     {
  108.         sprint (self,"Sorry, you must have at least 96\n");
  109.         sprint (self,"health, 50 nails, and 1 rocket\n"); 
  110.         sprint (self,"to fire a Motion Detector.\n");
  111.         return;
  112.     }
  113.  
  114.     // Take ammo & health requirements
  115.     self.health = self.health - 95;
  116.     self.ammo_nails = self.ammo_nails - 50;
  117.     self.ammo_rockets = self.ammo_rockets - 1;
  118.     W_SetCurrentAmmo();
  119.  
  120.     sprint (self,"You now have 10 seconds before the\n");
  121.     sprint (self,"  Motion Detector is activated.\n");
  122.  
  123.     detector = spawn();
  124.     detector.owner = self;
  125.     detector.movetype = MOVETYPE_TOSS;
  126.     detector.solid = SOLID_SLIDEBOX;
  127.     detector.classname = "motion_detector";
  128.     detector.netname = "Healthy Detector";
  129.  
  130.     detector.ammo_nails = 50;
  131.     detector.health = 100;
  132.     detector.weapon = IT_NAILGUN;  // This is the start of something big.
  133.  
  134.     detector.touch = MotionTouch_Moving;
  135.     detector.th_die = MotionThink_Destroy;
  136.     detector.takedamage = DAMAGE_AIM;
  137.  
  138. //    makevectors (self.v_angle);
  139.     detector.velocity = aim(self,10000) * 300;
  140.     detector.velocity_z = detector.velocity_z + 100;
  141.  
  142.     setmodel (detector,"progs/v_spike.mdl");    // Looks like Vore's missile.
  143.     setsize (detector, '-2 -2 -2', '2 2 2');
  144.     setorigin (detector, self.origin);
  145.     detector.origin_z = self.absmin_z + self.size_z * 0.7;
  146.  
  147. //    detector.think = MotionThink_Destroy;
  148. //    detector.nextthink = 20;  // If it has not been activated after 20 seconds,
  149.                           // assume it has fallen out of the world.  Destroy it.
  150. };
  151.  
  152. void() MotionTouch_Moving =
  153. {
  154.     if(other == self.owner || other == self)
  155.         return;
  156. //    if(other != world)
  157. //        return;
  158.  
  159.     self.velocity = '0 0 0';
  160.     self.movetype = MOVETYPE_NONE;
  161.  
  162.     self.touch = SUB_Null;
  163.  
  164.     self.think = MotionThink_Startup;
  165.     self.nextthink = time + 10;    // Startup delay
  166. };
  167.  
  168. void() MotionThink_Startup =
  169. {
  170.     local entity head;
  171.  
  172.     sprint (self.owner,"The Motion Detector is now active.\n");
  173.     self.think = MotionThink_Security;
  174.     self.nextthink = time + 0.05;
  175.  
  176.     head = findradius (self.origin, 750);
  177.     while(head)
  178.     {
  179.         if(head.classname == "motion_detector" && head != self)
  180.         {
  181.             traceline (self.origin, head.origin, TRUE, self);
  182.             if (trace_fraction == 1)
  183.             {
  184.                 if (self.think != MotionThink_Destroy)
  185.                     sprint (self.owner, "Motion Detector destroyed by proximity.\n");
  186.                 sprint (head.owner, "Motion Detector destroyed by proximity.\n");
  187.  
  188.                 self.think = MotionThink_Destroy;
  189. //                self.nextthink = time + 0.05;
  190.                 self.takedamage = 0;
  191.                 head.think = MotionThink_Destroy;
  192.                 head.nextthink = time + 0.05 + random();
  193.                 head.takedamage = 0;
  194.             }
  195.         }
  196.         head=head.chain;
  197.     }
  198. };
  199.  
  200. void() MotionThink_Security =
  201. {
  202.     local entity targ;
  203.  
  204.     self.nextthink = time + 0.05;    // Polling delay if no target
  205.     
  206.     targ = findradius (self.origin, 2000);
  207.     while(targ)
  208.     {
  209.         if(targ.takedamage && targ.owner != self)
  210.         {
  211.             if (targ.velocity != '0 0 0' || targ.moving_now)
  212.             {
  213.                 if (!(targ.flags & FL_NOTARGET))
  214.                 {
  215.                     
  216.                     traceline (self.origin, targ.origin, TRUE, self);   // see through other monsters
  217.  
  218.                     if (trace_fraction == 1)
  219.                     {
  220.                         // The target can be seen...  killed...
  221.                         
  222.                         if (self.weapon == IT_NAILGUN)
  223.                         {
  224.                             MotionFire_Nailgun(targ);
  225.                             if (self.ammo_nails == 0)
  226.                             {
  227.                                 Motion_SwitchWeapon();
  228.                             }
  229.                         }
  230.                     }
  231.                 }
  232.             }
  233.         }
  234.  
  235.         targ=targ.chain;
  236.     }
  237.  
  238. };
  239.  
  240. void(entity targ) MotionFire_Nailgun =
  241. {
  242.     local vector targ_loc,dir;
  243.     local float move_fract;
  244.     
  245.     // Lead the target slightly
  246.     // move_fract is based on the current distance to
  247.     // target, the speed of a nail, and the current speed
  248.     // of the target.  It should lead the target perfectly.
  249.     //  It doesn't, though.  :(
  250.     move_fract = vlen(targ.origin - self.origin)*1.000 / (1000.000 - vlen(targ.velocity)*1.000);
  251.     move_fract = move_fract * 0.600;  // Correct for inaccuracy
  252.     move_fract = move_fract + (random() / 20) - 0.025;
  253.     targ_loc = targ.origin + targ.velocity * move_fract;
  254.                     
  255.     traceline (self.origin, targ_loc, TRUE, self);   // see through other monsters
  256.                         
  257.     if(trace_fraction == 1)
  258.     {
  259.         // Target can be HIT.
  260.         dir = targ_loc - self.origin;
  261.         dir = normalize(dir);  // VERY important.  But why?
  262.  
  263.         sound (self,CHAN_WEAPON,"weapons/spike2.wav",1,ATTN_NORM);  // super spikes
  264.         launch_spike (self.origin, dir);
  265.         newmis.touch = MotionTouch_Spike;
  266.  
  267.         self.nextthink = time + 0.2;
  268.  
  269.         if(self.ammo_nails > 0)
  270.         {
  271.             self.ammo_nails = self.ammo_nails - 1;
  272.         } else {
  273.             // Out of ammo.  ... slow down.  :J
  274.             self.nextthink = time + 2;
  275.         }
  276.     }
  277. };
  278.  
  279. void() MotionThink_Destroy =
  280. {
  281.     local entity head;
  282.  
  283.     self.netname = "Dying Detector";
  284.  
  285.     head = findradius (self.origin, 100);
  286.     while(head)
  287.     {
  288.         if(head.classname == "motion_detector" && head != self)
  289.         {
  290.             head.think = MotionThink_Destroy;
  291.             head.nextthink = time + 0.05 + random();
  292.             head.takedamage = 0;
  293.         }
  294.         head=head.chain;
  295.     }
  296.  
  297.  
  298.     self.takedamage = 0;
  299.     T_RadiusDamage (self, self, 120, self);
  300.  
  301.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  302.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  303.     WriteCoord (MSG_BROADCAST, self.origin_x);
  304.     WriteCoord (MSG_BROADCAST, self.origin_y);
  305.     WriteCoord (MSG_BROADCAST, self.origin_z);
  306.  
  307.     BecomeExplosion ();
  308.     // This may do something else in the future...
  309. };
  310.  
  311. void() MotionTouch_Spike =
  312. {
  313.     if (other.solid == SOLID_TRIGGER)
  314.         return; // trigger field, do nothing
  315.  
  316.     if (pointcontents(self.origin) == CONTENT_SKY)
  317.     {
  318.         remove(self);
  319.         return;
  320.     }
  321.     
  322. // hit something that bleeds
  323.     if (other.takedamage)
  324.     {
  325.         spawn_touchblood (5);
  326.         T_Damage (other, self, self.owner, 5);
  327.     }
  328.     else
  329.     {
  330.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  331.         WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  332.         WriteCoord (MSG_BROADCAST, self.origin_x);
  333.         WriteCoord (MSG_BROADCAST, self.origin_y);
  334.         WriteCoord (MSG_BROADCAST, self.origin_z);
  335.     }
  336.  
  337.     remove(self);
  338. };
  339.  
  340. void() GiveMotionNails =
  341. {
  342.     local entity head;
  343.     local float to_give,reset_motion;
  344.     
  345.     if (self.ammo_nails < 1)
  346.     {
  347.         sprint (self, "You have no nails to give.\n");
  348.         return;
  349.     }
  350.  
  351.     if (self.ammo_nails > 25)
  352.     {
  353.         to_give = 25;
  354.     } else {
  355.         to_give = self.ammo_nails;
  356.     }
  357.  
  358.     head = findradius (self.origin, 120);
  359.     while(head)
  360.     {
  361.         if (head.classname == "motion_detector")
  362.         {
  363.             reset_motion = 1;
  364.             if (head.ammo_nails == 200)
  365.             {
  366.                 sprint (self, "Motion Detector is full.\n");
  367.                 reset_motion = 0;
  368.                 to_give = 0;
  369.             } else if (head.ammo_nails + to_give >= 200) {
  370.                 sprint (self, "Motion Detector is now full.\n");
  371.                 self.ammo_nails = self.ammo_nails - (200 - head.ammo_nails);
  372.                 head.ammo_nails = 200;
  373.                 to_give = 0;
  374.             } else {
  375.                 self.ammo_nails = self.ammo_nails - to_give;
  376.                 head.ammo_nails = head.ammo_nails + to_give;
  377.                 sprint (self, "Gave ");
  378. //                sprint (self, ftos (to_give));
  379.                 sprint (self, " nails to Motion Detector.\n");
  380.                 to_give = 0;
  381.             }
  382.  
  383.             if (head.nextthink <= (time + 5.0) && reset_motion)
  384.             {
  385.                 head.nextthink = time + 3.0;
  386.                 sprint (self, "You have 3 seconds to get away...\n");
  387.             }
  388.         }
  389.         head=head.chain;
  390.     }
  391.  
  392.     if(to_give)
  393.     {
  394.         sprint (self, "No Motion Detectors nearby.\n");
  395.     }
  396. };
  397.  
  398. void() Motion_SwitchWeapon =
  399. {
  400. };
  401.  
  402.  
  403.  
  404.